﻿#include "stdafx.h"
#include <unordered_map>
#include "AstFunction.h"
#include "FunctionInstance.h"
#include "TupleType.h"
#include "SiContext.h"
#include "utility.h"
#include "ClassInstanceType.h"
#include "AutoType.h"
#include "SArrayType.h"
#include "BlockContext.h"
#include "AstReturn.h"
#include "ClassContext.h"
#include "CodeGenerate/CallGen.h"
#include "CodeGenerate/CastGen.h"
#include "CodeGenerate/DefGen.h"
#include "CodeGenerate/ReturnGen.h"
#include "CodeGenerate/ParamenterGen.h"
#include "CodeGenerate/ClassMemberGen.h"
#include "utility.h"

void AstFunction::draw(std::ostream & os) {
	dotLable(os, "function " + name, "box");

	// std::string n = nodeId;
	// block->draw(os);
	// block->dotLable(os, "function " + name);
}

CodeGen * AstFunction::makeCast(std::vector<CodeGen*> cache, AstType * type, CodeGen * value)
{
	auto* p=new CastGen(type, value);
	cache.push_back(p);
	return p;
}

inline AstFunction::OrderedParameters* clearGen(
	AstFunction::OrderedParameters* ordered, 
	std::vector<CodeGen*> cache
) {
	for (auto * i : cache)
		delete i;
	delete ordered;
	return nullptr;
}

AstFunction::OrderedParameters* AstFunction::orderParameters(std::vector<std::pair<std::string, CodeGen*>>& types) {
	auto * ordered = new OrderedParameters();
	std::vector<CodeGen*> cache;  // 这里保存生成的转换器，匹配失败退出时，清理

	auto a = paremeters.begin();
	auto i = types.begin();
	for (; i != types.end() && a != paremeters.end(); a++, i++) {	// 先顺序匹配
		std::string& name = i->first;
		AstType* type = i->second->type;	// 参数的类型

		if (!name.empty() && a->name != name)
			break;	// 如果输入有名字，并且和当前位置不匹配，退出顺序匹配模式

		bool is = AutoType::isAuto(a->type);

		if (!is && !type->instanceOf(a->type))
			return clearGen(ordered, cache);		// 输入类型不匹配函数签名

		auto *v = makeCast(cache, a->type, i->second);
		ordered->parameters.push_back(std::make_pair(name.empty() ? a->name : name, v));
	}

	// 然后按名称匹配
	std::map<std::string, CodeGen*> indexes;
	// 先创建索引
	for (; i != types.end(); i++) {
		if (i->first.empty()) {
			if (variable) break;
			return clearGen(ordered, cache);	// 进入名字匹配模式时，参数都是需要有名字的
		}
		indexes.insert(std::make_pair(i->first, i->second));
	}

	// 然后按函数参数，找剩下的参数
	for (; a != paremeters.end(); a++) {
		auto x = indexes.find(a->name);
		if (x == indexes.end()) {
			if (a->defaultValue) {	// 有默认值
				ordered->parameters.push_back(std::make_pair(a->name, a->defaultValue));
			}
			else
				return clearGen(ordered, cache);
		}
		if (!x->second->type->instanceOf(a->type)) return nullptr;

		auto* v = makeCast(cache, a->type, x->second);
		ordered->parameters.push_back(std::make_pair(a->name, v));
		indexes.erase(x);
	}

	if (variable) for (; i != types.end(); i++) {	// 可变参数
		auto* v = makeCast(cache, variable, i->second);
		ordered->variableGen.push_back(v);
	}
	else if (!indexes.empty())	// 有多余未匹配的参数
		return clearGen(ordered, cache);
	return ordered;
}

AstType * AstFunction::getTypeByName(const std::string & name) {
	if (named.empty()) {
		for (auto &i : paremeters) {
			named[i.name] = i;
		}
	}
	auto iter = named.find(name);
	if (iter == named.end()) return nullptr;
	return iter->second.type;
}

CodeGen * AstFunction::makeCall(std::vector<std::pair<std::string, CodeGen*>>& types, CodeGen * object){
	OrderedParameters *ordered = orderParameters(types);
	if (!ordered) return nullptr;
	// 成功
	return createCallGen(ordered->parameters, ordered->variableGen, object);
}

/// <summary>
///  按函数签名保存
/// </summary>
std::unordered_map<std::string, FunctionInstance*> functionInstances;

CodeGen * AstFunction::makeGen(SiContext * parent)
{
	this->pathName = parent->pathName;

	// TODO: 判断是否构造函数
	parent->defineFunction( name, this );
	_parent = parent;

	// TODO: 如果非模板函数，直接生成签名 & 实现
	std::vector<std::pair<std::string, AstType*>> parameters;

	for (auto &i : paremeters) {
		if (AutoType::isAuto(i.type)) return nullptr;
		parameters.push_back(std::make_pair(i.name, i.type));
	}
	if (variable) {
		if (AutoType::isAuto(variable))
			return nullptr;
	}
	auto *c=dynamic_cast<ClassContext*>(parent);
	ClassInstanceType* cls = c ? c->getClassType() : nullptr;

	noTemplateInstance = getFunctionInstance(parameters, variable, cls);
	return nullptr;
}

CodeGen * AstFunction::createCallGen(
	std::vector<std::pair<std::string, CodeGen*>> parameterGens,
	std::vector<CodeGen*> variableGen,
	CodeGen* object,
	FunctionInstance* instance
)
{
	auto p = new CallGen();
	if (instance)
		p->function = instance;
	else {
		ClassInstanceType* o = object ? dynamic_cast<ClassInstanceType*>(object->type) : nullptr;
		p->function = getFunctionInstance(parameterGens, variableGen, o);
	}

	if (object) {
		p->params.push_back(object);
	}

	AstType*returnType=p->function->returnType;
	p->type = returnType;

	for (auto &i : parameterGens) {
		p->params.push_back(i.second);
	}

	for (auto &i : variableGen) {
		p->params.push_back(i);
	}
	return p;
}

FunctionInstance* AstFunction::getFunctionInstance(
	std::vector<std::pair<std::string, AstType*>> parameters,
	AstType* variableGen,
	ClassInstanceType* object) {
	if (this->noTemplateInstance) return this->noTemplateInstance;

	SiContext *s;
	auto *instance = new FunctionInstance();
	instance->name = encodeByHash(pathName) + "_" + name;

	// 如果是类，首参为类
	if (object) {
		s = new ClassContext(object->context, object);		// 类
		s->setSymbolValue("this", new ClassMemberGen());
		instance->object = object;
	}
	else {
		s = new BlockContext(_parent);
	}
	// 参数类型
	for (auto &i : parameters) {
		auto* p = new ParamenterGen();
		p->type = i.second;
		p->name = i.first;

		s->setSymbolValue(i.first, p);
		instance->parameters.push_back(std::make_pair(i.first, p->type));
	}

	// TODO: 可变参数
	if (variable) {
		if (AutoType::isAuto(variable)) {	 // 使用可变函数
			instance->variable = true;
		}
		else { // 类型确定的情况下，转为一个数组
			AstType* tp = new SArrayType(variable, 0);
			auto* p = new ParamenterGen();
			p->type = tp;
			p->name = variableName;
			s->setSymbolValue(variableName, p);
			instance->parameters.push_back(std::make_pair(variableName, tp));
		}
	}

	if (block.empty()) {
		std::vector<AstType*> types;
		for (auto &i : rets) {
			if (AutoType::isAuto(i.type))
				throw std::runtime_error("函数" + name + "无函数体，返回值必须明确定义类型");
			types.push_back(i.type);
		}
		instance->returnType = TupleType::create(std::move(types));
	} 
	else {
		// 生成函数体
		fillFunctionBlock(s, instance);
	}
	return instance;
}

void AstFunction::fillFunctionBlock(SiContext * s, FunctionInstance *instance)
{
	std::vector<CodeGen*> namedReturn;
	std::vector<AstType*>  returnTypes;
	// 初始化返回值
	for (auto i : rets) {
		if (!i.name.empty()) {
			auto *p = new DefGen();
			p->name = i.name;
			p->type = i.type;
			s->setSymbolValue(i.name, p);
			instance->block.push_back(p);
			namedReturn.push_back(p);
		}
		// returnTypes.push_back(i.type);
	}

	for (auto i : block) {
		auto a = i->makeGen(s);
		instance->block.push_back(a);

		auto r = dynamic_cast<ReturnGen*>(a);
		// 尝试通过 return 推导返回值类型
		if (r) {
			auto z1 = r->returnValues.begin();
			auto z2 = rets.begin();
			for (; z2 != rets.end(); z2++) {
				if (z1 == r->returnValues.end()) {	// return 后的参数已经结束
					if (!z2->name.empty()) {	// 填充命名的参数
						auto *p = s->findSymbolValue(z2->name, false);
						assert(p);
						r->returnValues.push_back(p);
						returnTypes.push_back(p->type);
					}
					else {
						throw std::runtime_error("return 语句返回的参数不足");
					}
				}
				else {
					auto *g = *z1;
					auto *x = dynamic_cast<AutoType*>(z2->type);
					if (x) {	// 需要推导
						x->setDeductive(g->type);
						returnTypes.push_back(g->type);
					}
					else {
						returnTypes.push_back(z2->type);
					}
					z1++;
				}
			}
		}
	}

	instance->returnType = TupleType::create(std::move(returnTypes));

	if (block.empty()) {
		instance->block.push_back(new ReturnGen());
		return;
	}

	auto *p = block.back();
	if (dynamic_cast<AstReturn*>(p))
		return;

	// 需要补全 Return (命名返回)
	auto *o = new ReturnGen();
	o->returnValues = std::move(namedReturn);
	instance->block.push_back(o);
}

FunctionInstance* AstFunction::getFunctionInstance(
	std::vector<std::pair<std::string, CodeGen*>> parameterGens,
	std::vector<CodeGen*> variableGen,
	ClassInstanceType* object)
{
	// 参数
	std::vector<std::pair<std::string, AstType*>> params;
	for (auto&i : parameterGens) {
		params.push_back(std::make_pair(i.first, i.second->type));
	}

	// 可变参数
	AstType* v = variable;
	if (!variableGen.empty()) {
		std::vector<AstType*> types;
		for (auto& i : variableGen) {
			types.push_back(i->type);
			if (AutoType::isAuto(v))
				v = i->type;
			else if (v && !i->type->instanceOf(v)) {
				v = nullptr;
			}
		}
		if (!v) v = TupleType::create(std::move(types));
	}

	return getFunctionInstance(params, v, object);
}
